package com.sql.pool;


import java.io.IOException;
import java.sql.Connection;

import java.sql.SQLException;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.sql.handler.Deploy;
import com.sql.handler.VectorConnection;
import com.sql.handler.util.CacheConnectionArray;

import com.sql.handler.util.LogFactory;


public class CacheConnectionPool extends AbstractConnectionPool{  
    
	/*线程安全数组*/
    private static volatile VectorConnection<Connection> pool = new VectorConnection<>();
    private static CacheConnectionArray mCacheConnectionArray = new CacheConnectionArray();
    private static volatile Connection selectConnection;
    /*不同于synchronized的另一种锁机制*/
    private final static Lock SELECT_LOCK = new ReentrantLock();
	
    /*构造方法，不做任何工作*/  
    private CacheConnectionPool() {}  
    
    /**
     * 做初始化工作
     * @throws InterruptedException 
     */
    private synchronized static void init() throws ClassNotFoundException, SQLException{
    	Logs.d("正在初始化连接池..");
    	if(!isOkConnection(selectConnection)){
    		selectConnection = load();
    	}
        Logs.d("初始化完毕");
    }
    
    /**
     * 得到select使用的连接，查询不同于其他三项，查询可以并发进行执行，
     * 所以我们只需提供一个连接来供所有用户使用
     */
    private static Connection getSelectConnection() throws SQLException, InterruptedException, ClassNotFoundException{
    	return isOkConnection(selectConnection) ? selectConnection : loadSelectConnection();
    }
    
    /**
     * 加载查询使用的连接
     * @return
     * @throws InterruptedException
     * @throws SQLException
     * @throws ClassNotFoundException 
     */
    private static Connection loadSelectConnection() throws InterruptedException, SQLException, ClassNotFoundException{
    	if(SELECT_LOCK.tryLock(8L,TimeUnit.SECONDS)){
    		if(!isOkConnection(selectConnection)){
    			selectConnection = load();
        	}
    		SELECT_LOCK.unlock();
    	}
    	Logs.d("成功拿到连接");
    	return selectConnection;
    }
    
    /**
     * 返回连接到连接池
     * 在这里进行控制，如果连接池里的连接数大于我们规定的数量，则对此连接进行关闭
     */
    private static void release(Connection con) throws SQLException, InterruptedException {
    	if(!isOkConnection(con)){
    		return;
    	}
    	if(pool.contains(con)){
    		return;
    	}
    	pool.add(con);
    	mCacheConnectionArray.add(con);
    	Logs.d("成功回收了连接！");
    }  
    
    /**
     * 新建连接
     * @return
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    private static Connection getNewConnection() throws SQLException, ClassNotFoundException{
    	Connection conn = load();
    	Logs.d("成功拿到新建连接！");
    	return isOkConnection(conn) ? conn : null;
    }
  
    /** 返回连接池中的一个数据库连接
     * 如果连接池中已经耗尽了Connextion  
     * 则创建新的使用 
     */
    private static Connection getConnection() throws ClassNotFoundException, InterruptedException, SQLException {    
    	Connection conn = getCacheConnection();
    	do{
    		conn = getNewConnection();
    	} while((!isOkConnection(conn)));
		return conn;
    }  
    
    /**
     * 得到缓存中的连接
     * @return
     * @throws SQLException
     */
    private static Connection getCacheConnection() throws SQLException{
    	while(pool.size() > 0){
    		Connection conn = getCacheConnectionHandler();
			if (isOkConnection(conn)) {
				Logs.d("成功拿到缓存池中的重用连接");
				return conn;
			}
		}
    	return null;
    }
    
    /**
     * 得到缓存中的连接的具体实现
     * @return
     * @throws SQLException
     */
    private static Connection getCacheConnectionHandler() throws SQLException{
    	if(pool.size() <= 0) {
    		return null;
    	}
    	Connection conn = pool.remove(0);
    	mCacheConnectionArray.remove(conn);
		return conn;
    }
    
    /**
     * 判断连接是否可以使用
     * @param con
     * @return
     * @throws SQLException
     */
    private static boolean isOkConnection(Connection con) throws SQLException{
    	if(con != null && !con.isClosed()){
    		if(!con.isValid(0)){
    			con.close();
    			return false;
    		}
    		return true;
    	}
    	return false;
    }
    
    /**
     * 加载连接
     * @return
     */
    private static Connection load() {	
    	return ConnectionLoad.load(DRIVER_CLASS_NAME, URL, USERNAME, PASSWORD);
    }
    
    /**
     * 获得缓存池中剩余连接的数量
     * @return
     */
    private static int getCacheCount(){
    	return pool.size();
    }
    
    /**
     * 关闭数据库连接池
     * @throws SQLException 
     */
    private static void closeConnectionPool() throws SQLException{
    	selectConnection.close();
    	URL = null;
    	USERNAME = null;
    	PASSWORD = null;
    	DRIVER_CLASS_NAME = null;
    	for(int i = 0;i < pool.size();i++){
    		pool.get(i).close();
    	}
    }
    
    /**
     * 内部静态类
     * 为外部访问提供接口
     * 
     * @author xvhuichuang
     * 
     */
    public static class Builder implements IBuilder {
	   
	   private Builder() {}
	   
	   /**
	    * 构造方法
	    * @param deploy
	    * @throws ClassNotFoundException
	    * @throws SQLException
	    * @throws IllegalAccessException
	    * @throws IOException
	    */
	   protected Builder(Deploy deploy)
			   throws ClassNotFoundException, SQLException, IllegalAccessException, IOException{
		   if(deploy == null){
			   throw new IllegalArgumentException("deploy参数不能为null");
		   }
		   if(!isRepeatPool(deploy)){
			   return;
		   }
			initData(deploy);
	   }
	   
	   /**
	    * 多连接池建立判断
	    */
	   private boolean isRepeatPool(Deploy aDeploy){
		   if(URL != null
				   && USERNAME != null 
				   && PASSWORD != null
				   && DRIVER_CLASS_NAME != null){
			   if(URL == aDeploy.getUrl() 
					   && USERNAME == aDeploy.getUser()
					   && PASSWORD == aDeploy.getPassword()
					   && DRIVER_CLASS_NAME == aDeploy.getDriverClassName()){
				   Logs.d("请不要重复初始化");
				   return false;
			   }
		   }
		   return true;
	   }
	   
	   /**
	    * 当程序被回收，这里进行恢复数据
	    * @param deploy
	    * @throws IllegalAccessException
	    * @throws ClassNotFoundException
	    * @throws SQLException
	    */
	   private void initData(Deploy deploy) throws IllegalAccessException, ClassNotFoundException, SQLException{
		   initDataHandler(deploy);
		   builderInit();
	   }
	   
	   /**
	    * 配置数据, 是否开启日志
	    * @param cacheSize
	    * @param newMaxSize
	    * @param cycleCheck
	    */
	   private void setConf(boolean isBoolean){
		   Logs = LogFactory.create(isBoolean);
	   }
	   
	   /**
	    * 恢复数据的实现方法
	    * @param deploy
	    * @throws IllegalAccessException
	    */
	   private void initDataHandler(Deploy deploy) throws IllegalAccessException{
		   URL = deploy.getUrl();
		   PASSWORD = deploy.getPassword();
		   USERNAME = deploy.getUser();
		   DRIVER_CLASS_NAME = deploy.getDriverClassName();
		   if(URL == null || PASSWORD == null || USERNAME == null || DRIVER_CLASS_NAME == null)
				throw new IllegalAccessException("url、driverClassName、password、user参数不能为空");
		   setConf(deploy.getCloseLog());
	   }
	   
	   /**
	    * 为外部提供初始化数据库连接池的接口
	    * @return
	    * @throws ClassNotFoundException
	    * @throws SQLException
	    */
	   private void builderInit() throws ClassNotFoundException, SQLException{
		   init();
	   }
	   
	   /**
	    * 为外部提供连接的接口
	    * @return
	    */
	   public Connection getBuilderConnection(){
		   try {
			return getConnection();
		} catch (ClassNotFoundException | InterruptedException | SQLException e) {
			e.printStackTrace();
		}
		   return null;
	   }
	   
	   /**
	    * 为外部提供得到查询连接的接口
	    * @return
	    */
	   public Connection getBuilderSelectConnection(){
		   try {
			   return getSelectConnection();
		   } catch (ClassNotFoundException | SQLException | InterruptedException e) {
			   e.printStackTrace();
		   }
		   return null;
	   }
	   
	   /**
	    * 为外部提供回收连接的接口
	    * @param con
	    */
	   public void builderRelease(Connection con){
		   try {
			   release(con);
		   } catch (SQLException | InterruptedException e) {
			   e.printStackTrace();
		   }
	   }
	   
	   /**
	    * 得到缓存池中的数量，这里提供一个供外部访问的接口
	    * @return
	    */
	   public int builderCacheCount(){
		   return getCacheCount();
	   }
	   
	   /**
	    * 得到新建连接的记录池中连接的数量，这里提供一个供外部访问的接口
	    */
	   public int builderNewCacheCount(){
		   return 0;
	   }
	   
	   /**
	    * 关闭数据库连接池，这里提供一个供外部访问的接口
	    */
	   public void builderCloseConnectionPool(){
		   try {
			closeConnectionPool();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	   }

    }
}  
